home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / xgrasp.zip / GIF.C < prev    next >
C/C++ Source or Header  |  1991-07-24  |  12KB  |  407 lines

  1. #ident "@(#)gif.c    1.5 91/04/01 XGRASP"
  2. /*-
  3.  * gif.c - routine to load GIF images (hacked from gif2ras).
  4.  *
  5.  * Copyright (c) 1991 by Patrick J. Naughton
  6.  *
  7.  * Permission to use, copy, modify, and distribute this software and its
  8.  * documentation for any purpose and without fee is hereby granted,
  9.  * provided that the above copyright notice appear in all copies and that
  10.  * both that copyright notice and this permission notice appear in
  11.  * supporting documentation.
  12.  *
  13.  * This file is provided AS IS with no warranties of any kind.  The author
  14.  * shall have no liability with respect to the infringement of copyrights,
  15.  * trade secrets or any patents by this file or any part thereof.  In no
  16.  * event will the author be liable for any lost revenue or profits or
  17.  * other special, indirect and consequential damages.
  18.  *
  19.  * Comments and additions should be sent to the author:
  20.  *
  21.  *                     Patrick J. Naughton
  22.  *                     Sun Microsystems
  23.  *                     2550 Garcia Ave, MS 10-20
  24.  *                     Mountain View, CA 94043
  25.  *                     (415) 336-1080
  26.  *
  27.  */
  28.  
  29. #include "grasp.h"
  30.  
  31. #define NEXTBYTE (*ptr++)
  32. #define IMAGESEP 0x2c
  33. #define INTERLACEMASK 0x40
  34. #define COLORMAPMASK 0x80
  35.  
  36. static int  BitOffset,    /* Bit Offset of next code */
  37.             XC, YC,    /* Output X and Y coords of current pixel */
  38.             Pass,    /* Used by output routine if interlaced pic */
  39.             OutCount,    /* Decompressor output 'stack count' */
  40.             RWidth, RHeight,    /* screen dimensions */
  41.             Width, Height,    /* image dimensions */
  42.             LeftOfs, TopOfs,    /* image offset */
  43.             BitsPerPixel,    /* Bits per pixel, read from GIF header */
  44.             ColorMapSize,    /* number of colors */
  45.             CodeSize,    /* Code size, read from GIF header */
  46.             InitCodeSize,    /* Starting code size, used during Clear */
  47.             LZWCode,    /* Value returned by ReadCode */
  48.             MaxCode,    /* limiting value for current code size */
  49.             ClearCode,    /* GIF clear code */
  50.             EOFCode,    /* GIF end-of-information code */
  51.             CurCode, OldCode, InCode,    /* Decompressor variables */
  52.             FirstFree,    /* First free code, generated per GIF spec */
  53.             FreeCode,    /* Decompressor, next free slot in hash table */
  54.             FinChar,    /* Decompressor variable */
  55.             BitMask,    /* AND mask for data size */
  56.             ReadMask,    /* Code AND mask for current code size */
  57.             Interlace, HasColormap;
  58.  
  59. static u_char *Image;    /* The result array */
  60. static u_char *RawGIF;    /* The heap array to hold it, raw */
  61. static u_char *Raster;    /* The raster data stream, unblocked */
  62.  
  63.  /* The hash table used by the decompressor */
  64. static int  Prefix[4096];
  65. static int  Suffix[4096];
  66.  
  67.  /* An output array used by the decompressor */
  68. static int  OutCode[1025];
  69.  
  70. static char *id = "GIF87a";
  71.  
  72.  
  73. /* Fetch the next code from the raster data stream.  The codes can be
  74.  * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
  75.  * maintain our location in the Raster array as a BIT Offset.  We compute
  76.  * the byte Offset into the raster array by dividing this by 8, pick up
  77.  * three bytes, compute the bit Offset into our 24-bit chunk, shift to
  78.  * bring the desired code to the bottom, then mask it off and return it.
  79.  */
  80. static int
  81. ReadCode()
  82. {
  83.     int         RawCode, ByteOffset;
  84.  
  85.     ByteOffset = BitOffset / 8;
  86.     RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
  87.     if (CodeSize >= 8)
  88.     RawCode += (0x10000 * Raster[ByteOffset + 2]);
  89.     RawCode >>= (BitOffset % 8);
  90.     BitOffset += CodeSize;
  91.     return (RawCode & ReadMask);
  92. }
  93.  
  94. static void
  95. AddToPixel(Index)
  96.     u_char      Index;
  97. {
  98.     *(Image + YC * Width + XC) = Index;
  99.  
  100. /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
  101.  
  102.     if (++XC == Width) {
  103.  
  104. /* If a non-interlaced picture, just increment YC to the next scan line.
  105.  * If it's interlaced, deal with the interlace as described in the GIF
  106.  * spec.  Put the decoded scan line out to the screen if we haven't gone
  107.  * past the bottom of it
  108.  */
  109.  
  110.     XC = 0;
  111.     if (!Interlace)
  112.         YC++;
  113.     else {
  114.         switch (Pass) {
  115.         case 0:
  116.         YC += 8;
  117.         if (YC >= Height) {
  118.             Pass++;
  119.             YC = 4;
  120.         }
  121.         break;
  122.         case 1:
  123.         YC += 8;
  124.         if (YC >= Height) {
  125.             Pass++;
  126.             YC = 2;
  127.         }
  128.         break;
  129.         case 2:
  130.         YC += 4;
  131.         if (YC >= Height) {
  132.             Pass++;
  133.             YC = 1;
  134.         }
  135.         break;
  136.         case 3:
  137.         YC += 2;
  138.         break;
  139.         default:
  140.         break;
  141.         }
  142.     }
  143.     }
  144. }
  145.  
  146.  
  147. ImageStruct *
  148. readgifimage(fp, dirent)
  149.     FILE       *fp;
  150.     FilenameStruct *dirent;
  151. {
  152.     ImageStruct *im;
  153.     XImage     *xim;
  154.     int         filesize;
  155.     u_char      ch, ch1;
  156.     u_char     *ptr, *ptr1;
  157.     int         i;
  158.  
  159.     BitOffset = 0;
  160.     XC = 0;
  161.     YC = 0;
  162.     Pass = 0;
  163.     OutCount = 0;
  164.  
  165.     im = (ImageStruct *) malloc(sizeof(ImageStruct));
  166.  
  167.     fseek(fp, dirent->offset, 0);
  168.  
  169.     filesize = GetLong(fp);    /* length of whole image file... */
  170.  
  171.     im->name = strtok(strdup(dirent->fname), ".");
  172.     im->type = EXT_GIF;
  173.     im->xoff = 0;
  174.     im->yoff = 0;
  175.  
  176.     if (!(ptr = RawGIF = (u_char *) malloc(filesize)))
  177.     error("%s: not enough memory to read gif file.\n", NULL);
  178.  
  179.     if (!(Raster = (u_char *) malloc(filesize)))
  180.     error("%s: not enough memory to read gif file.\n", NULL);
  181.  
  182.     if (fread(ptr, filesize, 1, fp) != 1)
  183.     error("%s: GIF data read failed\n", NULL);
  184.  
  185.     if (strncmp(ptr, id, 6)) {
  186.     free(im->name);
  187.     free(im);
  188.     free(Raster);
  189.     free(ptr);
  190.     return (ImageStruct *) readimage(fp, dirent, EXT_PIC);
  191.     }
  192.     ptr += 6;
  193.  
  194. /* Get variables from the GIF screen descriptor */
  195.  
  196.     ch = NEXTBYTE;
  197.     RWidth = ch + 0x100 * NEXTBYTE;    /* screen dimensions... not used. */
  198.     ch = NEXTBYTE;
  199.     RHeight = ch + 0x100 * NEXTBYTE;
  200.  
  201.     ch = NEXTBYTE;
  202.     HasColormap = ((ch & COLORMAPMASK) ? True : False);
  203.  
  204.     BitsPerPixel = (ch & 7) + 1;
  205.     im->cmaplen = 1 << BitsPerPixel;
  206.     BitMask = im->cmaplen - 1;
  207.  
  208.     ch = NEXTBYTE;    /* background color... not used. */
  209.  
  210.     if (NEXTBYTE)    /* supposed to be NULL */
  211.     error("%s: %s is a corrupt GIF file (nonull).\n", im->name);
  212.  
  213. /* Read in global colormap. */
  214.  
  215.     if (HasColormap) {
  216.     unsigned long pmasks;
  217.     u_long      pixels[256];
  218.  
  219.     im->cmap = XCreateColormap(dsp, win, vis, AllocNone);
  220.     XAllocColorCells(dsp, im->cmap, True, &pmasks, 0, pixels, im->cmaplen);
  221.  
  222.     for (i = 0; i < im->cmaplen; i++) {
  223.         im->colors[i].pixel = pixels[i];
  224.         im->colors[i].red = NEXTBYTE << 8;
  225.         im->colors[i].green = NEXTBYTE << 8;
  226.         im->colors[i].blue = NEXTBYTE << 8;
  227.         im->colors[i].flags = DoRed | DoGreen | DoBlue;
  228.  
  229.         if (imverbose) {
  230.         printf("%02x%02x%02x ",
  231.                im->colors[i].red >> 8,
  232.                im->colors[i].green >> 8,
  233.                im->colors[i].blue >> 8);
  234.         if (!((i + 1) % 8))
  235.             printf("\n");
  236.         }
  237.     }
  238.     XStoreColors(dsp, im->cmap, im->colors, im->cmaplen);
  239.     } else
  240.     im->cmap = (Colormap) 0;
  241.  
  242. /* Check for image seperator */
  243.  
  244.     if (NEXTBYTE != IMAGESEP)
  245.     error("%s: %s is a corrupt GIF file (nosep).\n", im->name);
  246. /* Now read in values from the image descriptor */
  247.  
  248.     ch = NEXTBYTE;
  249.     LeftOfs = ch + 0x100 * NEXTBYTE;
  250.     ch = NEXTBYTE;
  251.     TopOfs = ch + 0x100 * NEXTBYTE;
  252.     ch = NEXTBYTE;
  253.     Width = ch + 0x100 * NEXTBYTE;
  254.     ch = NEXTBYTE;
  255.     Height = ch + 0x100 * NEXTBYTE;
  256.     Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False);
  257.  
  258.     if (verbose)
  259.     fprintf(stderr, "%s: (GIF) %dx%dx%d %s\n",
  260.         im->name, Width, Height, 8,
  261.         (Interlace) ? "Interlaced" : "");
  262.  
  263. /* Note that I ignore the possible existence of a local color map.
  264.  * I'm told there aren't many files around that use them, and the spec
  265.  * says it's defined for future use.  This could lead to an error
  266.  * reading some files.
  267.  */
  268.  
  269. /* Start reading the raster data. First we get the intial code size
  270.  * and compute decompressor constant values, based on this code size.
  271.  */
  272.  
  273.     CodeSize = NEXTBYTE;
  274.     ClearCode = (1 << CodeSize);
  275.     EOFCode = ClearCode + 1;
  276.     FreeCode = FirstFree = ClearCode + 2;
  277.  
  278. /* The GIF spec has it that the code size is the code size used to
  279.  * compute the above values is the code size given in the file, but the
  280.  * code size used in compression/decompression is the code size given in
  281.  * the file plus one. (thus the ++).
  282.  */
  283.  
  284.     CodeSize++;
  285.     InitCodeSize = CodeSize;
  286.     MaxCode = (1 << CodeSize);
  287.     ReadMask = MaxCode - 1;
  288.  
  289. /* Read the raster data.  Here we just transpose it from the GIF array
  290.  * to the Raster array, turning it from a series of blocks into one long
  291.  * data stream, which makes life much easier for ReadCode().
  292.  */
  293.  
  294.     ptr1 = Raster;
  295.     do {
  296.     ch = ch1 = NEXTBYTE;
  297.     while (ch--)
  298.         *ptr1++ = NEXTBYTE;
  299.     if ((Raster - ptr1) > filesize)
  300.         error("%s: %s is a corrupt GIF file (unblock).\n", im->name);
  301.     } while (ch1);
  302.  
  303.     free(RawGIF);    /* We're done with the raw data now... */
  304.  
  305.     Image = (u_char *) malloc(Width * Height);
  306.     if (!Image)
  307.     error("%s: malloc failed on image data.\n");
  308.  
  309. /* Decompress the file, continuing until you see the GIF EOF code.
  310.  * One obvious enhancement is to add checking for corrupt files here.
  311.  */
  312.  
  313.     LZWCode = ReadCode();
  314.     while (LZWCode != EOFCode) {
  315.  
  316. /* Clear code sets everything back to its initial value, then reads the
  317.  * immediately subsequent code as uncompressed data.
  318.  */
  319.  
  320.     if (LZWCode == ClearCode) {
  321.         CodeSize = InitCodeSize;
  322.         MaxCode = (1 << CodeSize);
  323.         ReadMask = MaxCode - 1;
  324.         FreeCode = FirstFree;
  325.         CurCode = OldCode = LZWCode = ReadCode();
  326.         FinChar = CurCode & BitMask;
  327.         AddToPixel(FinChar);
  328.     } else {
  329.  
  330. /* If not a clear code, then must be data: save same as CurCode and InCode */
  331.  
  332.         CurCode = InCode = LZWCode;
  333.  
  334. /* If greater or equal to FreeCode, not in the hash table yet;
  335.  * repeat the last character decoded
  336.  */
  337.  
  338.         if (CurCode >= FreeCode) {
  339.         CurCode = OldCode;
  340.         OutCode[OutCount++] = FinChar;
  341.         }
  342. /* Unless this code is raw data, pursue the chain pointed to by CurCode
  343.  * through the hash table to its end; each code in the chain puts its
  344.  * associated output code on the output queue.
  345.  */
  346.  
  347.         while (CurCode > BitMask) {
  348.         if (OutCount > 1024) {
  349.             fprintf(stderr, "%s is a corrupt GIF file (OutCount).\n",
  350.                 im->name);
  351.             goto error_exit;
  352.         }
  353.         OutCode[OutCount++] = Suffix[CurCode];
  354.         CurCode = Prefix[CurCode];
  355.         }
  356.  
  357. /* The last code in the chain is treated as raw data. */
  358.  
  359.         FinChar = CurCode & BitMask;
  360.         OutCode[OutCount++] = FinChar;
  361.  
  362. /* Now we put the data out to the Output routine.
  363.  * It's been stacked LIFO, so deal with it that way...
  364.  */
  365.  
  366.         for (i = OutCount - 1; i >= 0; i--)
  367.         AddToPixel(OutCode[i]);
  368.         OutCount = 0;
  369.  
  370. /* Build the hash table on-the-fly. No table is stored in the file. */
  371.  
  372.         Prefix[FreeCode] = OldCode;
  373.         Suffix[FreeCode] = FinChar;
  374.         OldCode = InCode;
  375.  
  376. /* Point to the next slot in the table.  If we exceed the current
  377.  * MaxCode value, increment the code size unless it's already 12.  If it
  378.  * is, do nothing: the next code decompressed better be CLEAR
  379.  */
  380.  
  381.         FreeCode++;
  382.         if (FreeCode >= MaxCode) {
  383.         if (CodeSize < 12) {
  384.             CodeSize++;
  385.             MaxCode *= 2;
  386.             ReadMask = (1 << CodeSize) - 1;
  387.         }
  388.         }
  389.     }
  390.     LZWCode = ReadCode();
  391.     }
  392. error_exit:
  393.  
  394.     free(Raster);
  395.  
  396.     im->w = Width;
  397.     im->h = Height;
  398.     im->d = 8;
  399.     xim = XCreateImage(dsp, vis, im->d, ZPixmap, 0, Image,
  400.                im->w, im->h, 8, im->w);
  401.     im->pix = XCreatePixmap(dsp, win, im->w, im->h, 8);
  402.     XPutImage(dsp, im->pix, gc, xim, 0, 0, 0, 0, im->w, im->h);
  403.     XSync(dsp, False);
  404.     free(Image);
  405.     return im;
  406. }
  407.